package com.tyf.bookreader.manager;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tyf.bookreader.constant.RedisConstants;
import com.tyf.bookreader.domain.BrBook;
import com.tyf.bookreader.domain.BrHotbook;
import com.tyf.bookreader.dto.BookDto;
import com.tyf.bookreader.dto.BookInfoDto;
import com.tyf.bookreader.mapper.BrAuthorMapper;
import com.tyf.bookreader.mapper.BrBookMapper;
import com.tyf.bookreader.mapper.BrCategoryMapper;
import com.tyf.bookreader.mapper.BrHotbookMapper;
import com.tyf.bookreader.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Description 小说相关缓存业务
 * @Author shallow
 * @Date 2023/4/2 13:54
 */
@Slf4j
@Component
public class BookCacheManager {

    @Autowired
    private RedisService redisService;

    @Autowired
    private BrBookMapper bookMapper;

    @Autowired
    private BrCategoryMapper categoryMapper;
    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private BrAuthorMapper authorMapper;

    @Autowired
    private BrHotbookMapper hotbookMapper;

    public void addVisitCount(Long bookId){
        //首先查询缓存中是否有访问信息，如果有，则更新缓存中的信息，访问量+1，使用redis提供的原子操作
        Object count = redisService.hGet(RedisConstants.BOOK_VISIT_COUNT, String.valueOf(bookId));
        if(Objects.nonNull(count)){
            //缓存中有数据,自增
            redisService.hIncr(RedisConstants.BOOK_VISIT_COUNT,String.valueOf(bookId),1L);
            //异步更新数据库
        }
        //缓存中没有数据，去数据库中读,并放入缓存中
        //加分布式锁
        RLock lock = redissonClient.getLock(RedisConstants.REDISSON_LOCK_VISIT + bookId);
        try {
            lock.lock();
            Integer bookHasread = bookMapper.selectById(bookId).getBookHasread();
            redisService.hSet(RedisConstants.BOOK_VISIT_COUNT,String.valueOf(bookId),bookHasread+1,RedisConstants.COMMON_CACHE_TIME);
            log.debug("访问数{}",bookHasread+1);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public BookInfoDto getBookById(Long bookId){

        Object info = redisService.hGet(RedisConstants.BOOK_INFO_CACHE_KEY, String.valueOf(bookId));
        if (Objects.nonNull(info)){
            log.debug("走缓存");
            return BeanUtil.toBean(info,BookInfoDto.class);
        }
        //缓存未命中
        log.debug("走数据库");
        LambdaQueryWrapper<BrBook> wrapper = new LambdaQueryWrapper<BrBook>().eq(BrBook::getId, bookId).eq(BrBook::getDeleted, 0);
        BrBook bookInfo = bookMapper.selectOne(wrapper);
        if (Objects.isNull(bookInfo)){
            redisService.hSet(RedisConstants.BOOK_INFO_CACHE_KEY,String.valueOf(bookId),null,RedisConstants.COMMON_CACHE_TIME);
        }
        String categoryName = categoryMapper.selectById(bookInfo.getCategoryId()).getCategoryName();
        String authorName = authorMapper.selectById(bookInfo.getAuthorId()).getAuthorName();
        BookInfoDto bookInfoDto = BookInfoDto.builder()
                .id(bookInfo.getId())
                .categoryId(bookInfo.getCategoryId())
                .categoryName(categoryName)
                .bookDesc(bookInfo.getBookDesc())
                .bookImg(bookInfo.getBookImg())
                .bookName(bookInfo.getBookName())
                .authorId(bookInfo.getAuthorId())
                .authorName(authorName)
                .bookLastedChapter(bookInfo.getBookLatestChapter())
                .publisher(bookInfo.getBookPublish())
                .publishYear(bookInfo.getBookYear())
                .bookHasRead(bookInfo.getBookHasread())
                .bookStars(bookInfo.getBookStars())
                .bookPrice(bookInfo.getBookPrice()).build();
        redisService.hSet(RedisConstants.BOOK_INFO_CACHE_KEY,String.valueOf(bookId),bookInfoDto,RedisConstants.COMMON_CACHE_TIME);
        return bookInfoDto;
    }

    public List<BookDto> getHotBook() {
        if (redisService.lSize(RedisConstants.HOT_BOOK_CACHE_KEY)!=0) {
            log.debug("走缓存");
            return redisService.lRange(RedisConstants.HOT_BOOK_CACHE_KEY,0,-1)
                    .stream()
                    .map(v->BeanUtil.toBean(v,BookDto.class)).toList();
        }
        log.debug("走数据库");
        List<BrHotbook> hotbookList = hotbookMapper.selectList(new LambdaQueryWrapper<BrHotbook>()
                .eq(BrHotbook::getBookType, 1)
                .orderByDesc(BrHotbook::getSortWeight));
        List<BookDto> bookDtoList = hotbookList.stream().map(v -> {
            BrBook book = bookMapper.selectById(v.getBookId());
            if (Objects.isNull(book)) {
                return new BookDto();
            }
            BookDto bookDto = BookDto.builder().id(v.getBookId())
                    .bookName(book.getBookName())
                    .bookImg(book.getBookImg()).build();
            redisService.lPush(RedisConstants.HOT_BOOK_CACHE_KEY, bookDto,RedisConstants.COMMON_CACHE_TIME);
            return bookDto;
        }).toList();
        return bookDtoList;
    }
}
